package com.yxc.elastic.plugin.lcs;

import org.elasticsearch.script.DocReader;
import org.elasticsearch.script.ScoreScript;
import org.elasticsearch.search.lookup.SearchLookup;
import org.elasticsearch.search.lookup.Source;

import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * @author: YXC
 * @time: 2024/1/4 10:19
 **/
public class LcsSimilarityLeafFactory implements ScoreScript.LeafFactory {

    private final Map<String, Object> params;
    private final SearchLookup lookup;
    private final String fieldName;
    private final List<String> value;

//    private static final Log logger = LogFactory.getLog(LscSimilarityLeafFactory.class);

    LcsSimilarityLeafFactory(
            Map<String, Object> params, SearchLookup lookup) {
        // 校验params参数
        if (params.containsKey("fieldName") == false) {
            throw new IllegalArgumentException(
                    "Missing parameter [field]");
        }
        if (params.containsKey("value") == false) {
            throw new IllegalArgumentException(
                    "Missing parameter [term]");
        }
        this.params = params;
        this.lookup = lookup;
        fieldName = params.get("fieldName").toString();
        if (!(params.get("value") instanceof List)) {
            throw new IllegalArgumentException("value type Error! need List<String> but get " + params.get("value").getClass().getName());
        }
        value = ((List<String>) params.get("value"));
    }

    @Override
    public boolean needs_score() {
        return true;
    }

    @Override
    public ScoreScript newInstance(DocReader reader) throws IOException {
        Map<String, Object> source = reader.source().get().source();
        Source source1 = reader.source().get();
//        logger.info("计算score");
//        logger.info("field: " + fieldName + "  " + value);
        if (source.isEmpty() || !source.containsKey(fieldName) || !(source.get(fieldName) instanceof List)) {
            // 空文档，字段内容为空，字段类型不是List，返回0f
            return new ScoreScript(params, lookup, reader) {
                @Override
                public double execute(
                        ExplanationHolder explanation
                ) {
                    return returnError(params, lookup, reader, explanation);
                }
            };
        }
        return new ScoreScript(params, lookup, reader) {
            @Override
            public double execute(ExplanationHolder explanation) {
                return returnSuccess(params, lookup, reader, explanation, source().get().source());
            }
        };
    }

    /**
     * 字段为空返回
     *
     * @author YXC
     * @date 2024/1/5 10:35
     * @param params:
     * @param searchLookup:
     * @param docReader:
     * @param explanation:
     * @return double
    **/
    private double returnError(Map<String, Object> params, SearchLookup searchLookup, DocReader docReader,
                               ScoreScript.ExplanationHolder explanation) {
        return 0.0f;
    }

    /**
     * 计算相似度，并返回
     *
     * @author YXC
     * @date 2024/1/5 10:35
     * @param params:
     * @param searchLookup:
     * @param docReader:
     * @param explanation:
     * @param source: 当前文档的内容
     * @return double
    **/
    private double returnSuccess(Map<String, Object> params, SearchLookup searchLookup, DocReader docReader,
                                 ScoreScript.ExplanationHolder explanation, Map<String, Object> source) {
        // 每一个文档都要进行计算，此处需要优化
        // source为当前文档
        // TODO: 2024/1/4 添加获取校验
        List<String> list = (List<String>) source.get(fieldName);
        double lcsSimilarity = LCSSimilarity.getLCSSimilarity(value.toArray(new String[0]), list.toArray(new String[0]));
        return lcsSimilarity;
    }
}
